package eu.jakubiak.ioc
{
	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;
	import flash.utils.describeType;
	
	import mx.binding.utils.BindingUtils;
	
	[IocBean(name="ioc")]
	public class Ioc extends EventDispatcher
	{
		
		private static var instance:Ioc;
		
		public static function getInstance():Ioc {
			if(instance==null) {
				instance = new Ioc();
				instance.manage(instance);	
			}
			return instance;
		}
		
		
		public function Ioc()
		{
		}

		/**
		 * Set of managed objects
		 */
		private var beans:Dictionary = new Dictionary();
		
		
		/**
		 * Add new object to maneged objects set
		 */
		public function manage(bean:Object, name:String=null):void {
			var description:XML = describeType(bean);
			var beanDesc:XMLList = description.metadata.(@name=="IocBean");
			var bindsDesc:XMLList = description..metadata.(@name=="IocBind");
			
			if(name==null) {
				if(beanDesc.length()==1) {
					name = beanDesc.arg.(@key="name").@value;
				} else {
//					name = description.@name;
//					name = name.replace(/.*::/,"");
//					name = name.charAt(0).toLowerCase() + name.substring(1);
				}
			} 
			// wstawienie do puli obiektów zarządzanych
			if(name!=null) {
				if(this.beans[name] != null) {
					this.beans[name].bean = bean;
				} else {
					this.beans[name] = new BeanWrapper(bean);
				}
			}
			
			
			// zarządzanie zależnościami
			for each(var bindDesc:XML in bindsDesc) {
				var destinationPropertyName:String = bindDesc.parent().@name;
				var sourcePropertyName:String = bindDesc.arg.(@key=="name").@value;
				if(sourcePropertyName==""||sourcePropertyName==null) {
					sourcePropertyName = destinationPropertyName;
				}
				// powiązanie
				if(this.beans[sourcePropertyName] == undefined) {
					this.beans[sourcePropertyName] = new BeanWrapper();
				} else {
					bean[destinationPropertyName] = this.beans[sourcePropertyName].bean;
				}
				// wiazanie dwukierunkowe
				BindingUtils.bindProperty(bean, destinationPropertyName, this.beans, [sourcePropertyName,"bean"]);
				BindingUtils.bindProperty(this.beans[sourcePropertyName], "bean", bean, destinationPropertyName);
			}
		}
		
		/**
		 * Add all beans to maneged beans set
		 */
		public function manageAll(... beans):void {
			for each (var bean:* in beans) {
				manage(bean);
			}
		}		

	}
}